<?php
/**
 * Created by PhpStorm.
 * User: ytlmi
 * Date: 2018/3/7
 * Time: 11:15
 */

namespace org\util\forensictool\forensicreport;

use org\util\wordTool\Table;
use org\util\wordTool\Word;
use org\util\forensicTool\LittleTools;

abstract class BaseReport
{
    protected $caseData = [];//案件信息
    protected $genoType = [];//样品分型数据
    protected $Kit = [];//试剂盒信息，包含全名、厂家
    protected $frequency = [];//基因频率库
    protected $mutation = [];//突变率
    protected $appraiser = [];//鉴定人数据
    protected $config = [];//配置数据
    protected $describe;
    protected $conclude;
    protected $describe_fob='';
    protected $conclude_fob='';
    protected static $instance;// 对象实例
    protected $templatePath;
    protected $reportPath;

    const BODY_FONT = ['name' => '仿宋_GB2312', 'size' => '四号'];
    const TABLE_DES_FONT = ['name' => '仿宋_GB2312', 'size' => '五号'];
    const TABLE_FONT = ['name_zh' => '仿宋_GB2312', 'name_en' => 'Times New Roman', 'size' => '五号'];
    const HEAD_FONT_1 = ['name' => '黑体', 'size' => '小二'];
    const HEAD_FONT_2 = ['name' => '黑体', 'size' => '三号'];
    const HEAD_FONT_3 = ['name' => '黑体', 'size' => '四号'];
    const TEXT_CENTER = ['align' => 'center'];
    const TEXT_RIGHT = ['align' => 'right'];
    const TEXT_LEFT = ['align' => 'left'];
    const TEXT_TAB = ['chars' => 200];
    const TABLE_STYLE = ['border' => ['top' => 'type=single,size=12', 'bottom' => 'type=single,size=12']];
    const FIRST_ROW_STYLE = ['align' => 'center', 'vAlign' => 'center', 'border' => ['bottom' => 'type=single,size=4']];
    const MID_ROW_STYLE = ['align' => 'center', 'vAlign' => 'center', 'border' => ['top' => 'type=nil', 'bottom' => 'type=nil']];
    const LAST_ROW_STYLE = ['align' => 'center', 'vAlign' => 'center', 'border' => []];


    /**
     * @return BaseReport
     * 单例模式实例化当前类
     */
    static public function instance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new static();
        }
        return self::$instance;
    }

    /**
     * @param array $caseData
     * @return BaseReport
     * @throws \Exception
     */
    public function setCaseData(array $caseData)
    {
        $dataMap = ['case_id', 'case_type', 'client_type', 'client_name', 'case_info', 'request_date', 'accept_date', 'end_date', 'id_kit', 'id_appraiser_0', 'id_appraiser_1', 'samples'];
        foreach ($dataMap as $item) {//验证数据完整性
            if (!isset($caseData[$item])) throw new \Exception('案件信息缺少:' . $item);
        }
        $this->caseData = $caseData;
        return $this;
    }

    /**
     * @param array $genoType
     * @return BaseReport
     */
    public function setGenoType(array $genoType)
    {
        $this->genoType = $genoType;
        return $this;
    }

    /**
     * @param array $arrKit
     * @return BaseReport
     * @throws \Exception
     */
    public function setKit(array $arrKit)
    {
        $this->Kit = $arrKit;
        return $this;
    }

    /**
     * @param array $frequency
     * @return BaseReport
     */
    public function setFrequency(array $frequency)
    {
        $this->frequency = $frequency;
        return $this;
    }

    /**
     * @param array $mutation
     * @return BaseReport
     */
    public function setMutation(array $mutation)
    {
        $this->mutation = $mutation;
        return $this;
    }

    /**
     * @param array $appraiser
     * @return BaseReport
     * 以id为索引
     */
    public function setAppraiser(array $appraiser)
    {
        $this->appraiser = $appraiser;
        return $this;
    }

    /**
     * @param array $config
     * @return BaseReport
     * 报告使用的配置，包含：机构名称(instFullName),机构简称(instShortName),
     */
    public function setConfig(array $config)
    {
        $this->config = $config;
        return $this;
    }

    /**
     * @throws \Exception
     */
    public function makeReport()
    {
        $tool=LittleTools::instance();
        $this->makeDescribe();
        $rep = [
            //机构名称
            '{INST_NAME}'         => $this->config['inst_name'],
            //机构简称
            '{INST_BRIEF}'        => $this->config['inst_brief'],
            //年份
            '{YEAR_NOW}'          => date('Y'),
            //案件序号
            '{CASE_ID}'           => $this->getReportNum(),
            //委托方类型
            '{CLIENT_TYPE}'       => $this->getClientType(),
            //委托方名称
            '{CLIENT_NAME}'       => $this->caseData['client_name'],
            //鉴定事项
            '{CASE_ISSUE}'        => $this->makeCaseIssue(),
            //委托日期
            '{REQUEST_DATE}'      => $tool->dateToZh($this->caseData['request_date']),
            //受理日期
            '{ACCEPT_DATE}'       => $tool->dateToZh($this->caseData['accept_date']),
            //鉴定材料
            '{SAMPLE_TYPE}'       => $this->makeSampleTypes(),
            //鉴定日期
            '{DETECT_DATE}'       => $tool->dateToZh($this->caseData['accept_date'],'en').'至'.$tool->dateToZh($this->caseData['end_date'],'en'),
            //样品/被鉴定人列表
            '{SAMPLE_TABLE}'      => $this->makeSampleTable(),
            //基本案情
            '{CASE_INFO}'         => $this->caseData['case_info'],
            //实验室检验规范
            '{STANDARD_LAB}'      => $this->config['standard_lab'],
            //试剂盒全称
            '{KIT_NAME}'          => $this->Kit[$this->caseData['id_kit']]['kit_describe'],
            //试剂盒厂家
            '{KIT_COMPANY}'       => $this->Kit[$this->caseData['id_kit']]['kit_company'],
            //检测设备名称
            '{EQUIPMENT_NAME}'    => $this->config['equipment_name'],
            //检测设备厂家
            '{EQUIPMENT_COMPANY}' => $this->config['equipment_company'],
            //分析用软件
            '{ANALYZE_SOFTWARE}'  => $this->config['analyze_software'],
            //检测结果表
             '{DETECTION_TABLES}'  => $this->makeDetectionTable(),
            //分析说明
            '{DESCRIBE}'          => $this->describe,
            //结论
            '{CONCLUDE}'          => $this->conclude,
            //分析说明
            '{DESCRIBE_FOB}'      => $this->describe_fob,
            //结论
            '{CONCLUDE_FOB}'      => $this->conclude_fob,
            //落款
            '{APPRAISER_NAME_1}'  => $this->makeAppraiserCalling($this->caseData['id_appraiser_0']),
            '{APPRAISER_NAME_2}'  => $this->makeAppraiserCalling($this->caseData['id_appraiser_1']),
            '{APPRAISER_NUM_1}'   => $this->appraiser[$this->caseData['id_appraiser_0']]['number'],
            '{APPRAISER_NUM_2}'   => $this->appraiser[$this->caseData['id_appraiser_1']]['number'],
            //落款日期
            '{END_DATE}'          => $tool->dateToZh($this->caseData['end_date']),
        ];
        $templateName= $this->caseData['case_type'] == 'ty' ? 'report_ty.docx' : 'report_qz.docx';
        $reportTemplate = $_SERVER['DOCUMENT_ROOT'].'/template/forensic/'.$templateName;
        $reportSavePath = $_SERVER['DOCUMENT_ROOT'].'/report/forensic/'.$this->caseData['case_id'].'.docx';
        Word::instance()->setTemplate($rep,$reportTemplate,$reportSavePath);
    }

    /**
     * @throws \Exception
     */
    public function makeHandover()
    {
        $sampleCount=function ()
        {
            $arr_sampleType=[];
            $str_sampleType='';
            foreach ($this->caseData['samples'] as $sample) {
                if(isset($arr_sampleType[$sample['sample_type']])){
                    $arr_sampleType[$sample['sample_type']] ++ ;
                }else{
                    $arr_sampleType[$sample['sample_type']] =1;
                }
            }
            foreach ($arr_sampleType as $type=>$count) {
                $str_sampleType.=$type.$count.'份，';
            }
            return $str_sampleType;
        };

        $rep=[
            //案件名
            '{CASE_NAME}'   => $this->caseData['case_id'],
            //受理日期
            '{ACCEPT_DATE}' => LittleTools::instance()->dateToZh($this->caseData['accept_date'],'en'),
            //样品类型计数
            '{SAMPLE_COUNT}'=> $sampleCount(),
        ];
        $reportTemplate = $_SERVER['DOCUMENT_ROOT'].'/template/forensic/handover.docx';
        $reportSavePath = $_SERVER['DOCUMENT_ROOT'].'/report/forensic/'.$this->caseData['case_id']. iconv('UTF-8','GB2312//IGNORE','-交接单.docx') ;
        Word::instance()->setTemplate($rep,$reportTemplate,$reportSavePath);
    }

    public function makeRecord()
    {
        $rep=[
            //案件序号
            '{CASE_ID}'         => $this->caseData['case_id'],
            //委托方类型
            '{CLIENT_TYPE}'     => $this->getClientType(),
            //委托方名称
            '{CLIENT_NAME}'     => $this->caseData['client_name'],
            //提取试剂盒
            '{EXTRACT_KIT_NAME}' => $this->Kit[$this->caseData['id_extract']]['kit_describe'],
            '{EXTRACT_KIT_LOT}' => $this->Kit[$this->caseData['id_extract']]['kit_lot'],
            //检测试剂盒
            '{DETECT_KIT_NAME}' => $this->Kit[$this->caseData['id_kit']]['kit_describe'],
            '{DETECT_KIT_LOT}'  => $this->Kit[$this->caseData['id_kit']]['kit_lot'],
        ];

        $sampleID=[];
        foreach ($this->caseData['samples'] as $sample) {
            $sampleID[]=$sample['sample_name'];
        }

        for ($i=0;$i<count($sampleID);$i++){
            $rep['{EXTRACT'.$i.'}']=$sampleID[$i];
            $rep['{PCR' . $i . '}'] = $sampleID[$i];
            $rep['{DNA' . $i . '}'] = $sampleID[$i];
            $rep['{DETECT' . $i . '}'] = $sampleID[$i];
        }

        for ($i=0;$i<8;$i++){
            if ($i>=count($sampleID)){
                if ($i==count($sampleID)){
                    $rep['{EXTRACT'.$i.'}']='';
                    $rep['{PCR' . $i . '}'] = '9947A';
                    $rep['{DNA' . $i . '}'] = '9947A';
                    $rep['{DETECT' . $i . '}'] = '9947A';
                }elseif($i==(count($sampleID)+1)){
                    $rep['{EXTRACT'.$i.'}']='';
                    $rep['{PCR' . $i . '}'] = 'NT';
                    $rep['{DNA' . $i . '}'] = 'H20';
                    $rep['{DETECT' . $i . '}'] = 'NT';
                }else{
                    $rep['{EXTRACT'.$i.'}']='';
                    $rep['{PCR' . $i . '}'] = '';
                    $rep['{DNA' . $i . '}'] = '';
                    $rep['{DETECT' . $i . '}'] = '';
                }
            }
        }
        return $rep;
    }

    //reportNum
    protected function getReportNum()
    {
        $caseID = $this->caseData['case_id'];
        if (preg_match('/\d\d-DNA-\d+/', $caseID)) {
            $split = preg_split('/\d\d-DNA-/', $caseID);
            $reportNum = $split[1];
        } elseif (preg_match('/\d+/', $caseID) && strlen($caseID) < 4) {
            $reportNum = $caseID;
        } else {
            $reportNum = 'XX';
        }
        return $reportNum;
    }

    protected function getClientType()
    {
        $clientTypeMap = ['委 托 人', '委托单位'];
        return $clientTypeMap[$this->caseData['client_type']];
    }


    /**
     * @return array
     * 将样品按角色分组,亲子鉴定分为亲代子代两组,个体识别分为已知样和未知样两组
     */
    protected function makeRoleGroup()
    {
        $roleGroup = [[], []];
        foreach ($this->caseData['samples'] as $role => $sample) {
            if (preg_match('/(F|M|yz)/', $role)) $roleGroup[0][] = $role;
            if (preg_match('/(C|wz)/', $role)) $roleGroup[1][] = $role;
        }
        return $roleGroup;
    }

    /**
     * @return string
     * 根据样品分组生成鉴定事项文本
     */
    protected function makeCaseIssue()
    {
        $roleGroup = $this->makeRoleGroup();
        $nameStr0 = '';
        $nameStr1 = '';
        if ($this->caseData['case_type'] == 'ty') {
            $caseMatter = '同一性认定';
        } else {
            foreach ($roleGroup[1] as $role) {//用顿号连接孩子姓名
                $nameStr1 .= $this->caseData['samples'][$role]['person_name'] . '、';
            }
            if ($this->caseData['case_type'] == '3l') {
                $nameStr0 = $this->caseData['samples']['F']['person_name'] . '、';
            } else {
                foreach ($roleGroup[0] as $role) {//用顿号连接父母姓名
                    $nameStr0 .= $this->caseData['samples'][$role]['person_name'] . '、';
                }
            }
            $nameStr0 = mb_substr($nameStr0, 0, -1);
            $nameStr1 = mb_substr($nameStr1, 0, -1);
            $caseMatter = '检验' . $nameStr0 . '与' . $nameStr1 . '之间是否存在亲生血缘关系';
        }
        return $caseMatter;
    }

    /**
     * @return string
     * 生成鉴定材料描述文本
     */
    protected function makeSampleTypes()
    {
        $sampleTypes = '';
        foreach ($this->caseData['samples'] as $sample) {
            $sampleTypes .= $this->caseData['case_type'] == 'ty' ? $sample['sample_type'] . '、' : $sample['person_name'] . $sample['sample_type'] . '、';
        }
        return mb_substr($sampleTypes, 0, -1);
    }

    /**
     * @param mixed $appraiserId
     * @return string
     * 生成鉴定人描述
     */
    protected function makeAppraiserCalling($appraiserId)
    {
        $calling = $this->appraiser[$appraiserId]['calling'];
        $spaceCount=15-(2*mb_strlen($calling));
        for($i=0;$i<$spaceCount;$i++){
            $calling .= ' ';
        }
        $calling .= $this->appraiser[$appraiserId]['name'];
        return $calling;
    }

    /**
     * @param string $formula
     * @return string
     * 格式化公式
     */
    protected function makeFormula($formula)
    {
        preg_match_all('/{[0-9\.]+}/', $formula, $matches);
        foreach ($matches[0] as $match) {
            $sub = preg_replace('/[{}]/', '', $match);
            $formula = str_replace($match, '</w:t></w:r><w:r><w:rPr><w:vertAlign w:val="subscript"/></w:rPr><w:t>'.$sub.'</w:t></w:r><w:r><w:t>', $formula);
        }
        $formula = str_replace('^2', '</w:t></w:r><w:r><w:rPr><w:vertAlign w:val="superscript"/></w:rPr><w:t>2</w:t></w:r><w:r><w:t>', $formula);
        return $formula;
    }

    protected abstract function makeSampleTable();

    protected abstract function addRow(Table $table, $role, $position = 'mid');

    protected abstract function makeDetectionTable();

    protected abstract function makeDescribe();

}